﻿using System;
using System.Collections.Generic;
using CI.Mesopotamia;
using CI.Mesopotamia.Dal;
using CI.Mesopotamia.WebService;
using CI.Misc;
using CI.Organism;
using CI.Utils;
using NUnit.Framework;
using CI.Interfaces;
using CI;

namespace MesopotamiaDCProxy.SystemTests
{
    [TestFixture]
    public class ScenarioTests
    {

        InboundClient _wsClient;
        const string SCENARIO_NAME = "Survival of the Fattest - System Tests - Scenario";
        Scenario _scenario;
        IHostingEnvironment _hostingEnvironment;
        const string HOST_VERSION = "hostVersion";
        const string MACHINE_NAME = "machineName";
        private int _userId;
        private SimEnv _simEnv = SimEnv.Instance;

        /// <summary>
        /// setup tests
        /// </summary>
        [SetUp]
        public void Setup()
        {
            _wsClient = new InboundClient();

            _simEnv.TraceLogger.LogDebug(string.Format("Using endpoint {0}", _wsClient.Endpoint.Address));

            Globals.LaunchedFrom = LaunchType.CommandLine;

            #region Create Scenario
            _scenario = new ScenarioLocalXML();
            _scenario.FitnessFunction = typeof(CollisionDetection).ToString();
            _scenario.ScenarioName = SCENARIO_NAME;
            _scenario.ScenarioDescription = "The evolutionary objective is for the fattest one to reproduce and evolve";
            _scenario.ManifestFile = "InABox.Manifest.xml";
            _scenario.BoundryXRadiusMax = 3.2f;
            _scenario.BoundryYRadiusMax = 2.5f;
            _scenario.BoundryZRadiusMax = 3.2f;
            _scenario.MaxLoadCount = 10;
            _scenario.MaxSaveCount = 11;
            _scenario.SimulationRestrictions = typeof(SurvivalFattest).ToString();
            _scenario.RequiredOrganisms = new List<IScenarioEntityRequirements>();
            _hostingEnvironment = new MSRBHost(new MockHostingEnvironmentPhysical(), _scenario);
            var amoebas = new Scenario.ScenarioEntityRequirements();
            var iRobots = new Scenario.ScenarioEntityRequirements();
            _scenario.RequiredOrganisms.Add(amoebas);
            _scenario.RequiredOrganisms.Add(iRobots);
            amoebas.OrganismType = new Amoeba(new Organism(_hostingEnvironment), Guid.NewGuid());
            iRobots.OrganismType = new iRobot(new Organism(_hostingEnvironment), Guid.NewGuid());

            // null out sub sections
            amoebas.OrganismType.Organism = null;
            iRobots.OrganismType.Organism = null;
            amoebas.OrganismType.Guid = Guid.Empty;
            iRobots.OrganismType.Guid = Guid.Empty;
            amoebas.UseFallBackOnly = true;
            iRobots.UseFallBackOnly = false;

            // add the location
            amoebas.Locations.Add(new Location(-1.5f, 0.1f, 1.5f, 0.1f, 0.1f, 0.1f));
            amoebas.Locations.Add(new Location(-1.5f, 0.1f, -1.5f, 0.1f, 0.1f, 0.1f));
            amoebas.Locations.Add(new Location(1.5f, 0.1f, 1.5f, 0.1f, 0.1f, 0.1f));
            amoebas.Locations.Add(new Location(1.5f, 0.1f, -1.5f, 0.1f, 0.1f, 0.1f));
            iRobots.Locations.Add(new Location(0.5f, 0.1f, 0, 0.2f, 0.1f, 0.2f));
            iRobots.Locations.Add(new Location(-0.5f, 0.1f, 0, 0.2f, 0.1f, 0.2f));

            // load dal
            IDAL dal = new TestDAL();
            _hostingEnvironment = dal.LoadHostingEnvironment("dont care", _hostingEnvironment, 0, new List<Guid>());

            // add the fall back organisms
            _scenario.FallBackOrganisms = new List<IOrganism>(_hostingEnvironment.Organisms.Alive);

            _userId = _wsClient.GetNewUserId(MACHINE_NAME, HOST_VERSION);

            #endregion

        }

        /// <summary>
        /// teardown
        /// </summary>
        [TearDown]
        public void TearDown()
        {
            bool deleteResult;

            // Cleanup
#if !PUBLISHRELEASE
            if (_scenario.ScenarioName != null)
                deleteResult = _wsClient.DeleteScenario(_scenario.ScenarioName, _userId);
#endif
            _wsClient.Close();
        }

#if !PUBLISHRELEASE
        /// <summary>
        /// Load a scenario webservice
        /// </summary>
        [Test]
        public void LoadScenarioWSNotNull()
        {

            // get the user id
            _userId = _wsClient.GetNewUserId(MACHINE_NAME, HOST_VERSION);

            // delete the old scenario if exists
            _wsClient.DeleteScenario(_scenario.ScenarioName, _userId);

            // save the new scenario
            _wsClient.SaveScenario(_scenario, _userId);

            Assert.IsNotNull(_wsClient.LoadScenario(SCENARIO_NAME, _userId), "No scenarion returned");
        }
#endif


#if !PUBLISHRELEASE
        /// <summary>
        /// Create a scenario and save it to the DB directly, load it back from the webservice and check and make sure its the same
        /// </summary>
        [Test]
        public void SaveLoadScenarioWSTrue()
        {
            // get the user id
            _userId = _wsClient.GetNewUserId(MACHINE_NAME, HOST_VERSION);

            // delete the old scenario if exists
            _wsClient.DeleteScenario(_scenario.ScenarioName, _userId);

            // save the new scenario
            _wsClient.SaveScenario(_scenario, _userId);

            // load it back in
            var loadedScenario = _wsClient.LoadScenario(_scenario.ScenarioName, _userId);

            // compare it
            Assert.IsTrue(_scenario.EqualsValueTypes(loadedScenario), "saved scenario is not the same as loaded");
        }
#endif
        /// <summary>
        /// ask the web service for a list of scenarios
        /// </summary>
        [Test]
        public void GetScenarioListWS()
        {
            // get the user id
            _userId = _wsClient.GetNewUserId(MACHINE_NAME, HOST_VERSION);
            int scenearioCount = _wsClient.GetScenarioList(HOST_VERSION, _userId).Length;
            Assert.Greater(scenearioCount, 0, "No scenarios returned in list");
        }


        /// <summary>
        /// not really a test just a method to save the survival of the fattest scenario
        /// </summary>
        [Test, Category("ScenarioCreate")]
        public void SaveScenarioSurvivalFittestWS()
        {
            _scenario = new ScenarioLocalXML();
            _scenario.FitnessFunction = typeof(CollisionDetection).ToString();
            _scenario.ScenarioName = "Survival of the Fattest";
            _scenario.ScenarioDescription = "The evolutionary objective is for the fattest one to reproduce and evolve";
            _scenario.ManifestFile = "InABox.Manifest.xml";
            _scenario.BoundryXRadiusMax = 3.2f;
            _scenario.BoundryYRadiusMax = 2.5f;
            _scenario.BoundryZRadiusMax = 3.2f;
            _scenario.MaxLoadCount = 10;
            _scenario.MaxSaveCount = 11;
            _scenario.SimulationRestrictions = typeof(SurvivalFattest).ToString();
            _scenario.RequiredOrganisms = new List<IScenarioEntityRequirements>();
            _hostingEnvironment = new MSRBHost(new MockHostingEnvironmentPhysical(), _scenario);
            var amoebas = new Scenario.ScenarioEntityRequirements();
            var iRobots = new Scenario.ScenarioEntityRequirements();
            _scenario.RequiredOrganisms.Add(amoebas);
            _scenario.RequiredOrganisms.Add(iRobots);
            amoebas.OrganismType = new Amoeba(new Organism(_hostingEnvironment), Guid.NewGuid());
            iRobots.OrganismType = new iRobot(new Organism(_hostingEnvironment), Guid.NewGuid());

            // null out sub sections
            amoebas.OrganismType.Organism = null;
            iRobots.OrganismType.Organism = null;
            amoebas.OrganismType.Guid = Guid.Empty;
            iRobots.OrganismType.Guid = Guid.Empty;
            amoebas.UseFallBackOnly = true;
            iRobots.UseFallBackOnly = false;

            // add the location
            amoebas.Locations.Add(new Location(-1.5f, 0.1f, 1.5f, 0.1f, 0.1f, 0.1f));
            amoebas.Locations.Add(new Location(-1.5f, 0.1f, -1.5f, 0.1f, 0.1f, 0.1f));
            amoebas.Locations.Add(new Location(1.5f, 0.1f, 1.5f, 0.1f, 0.1f, 0.1f));
            amoebas.Locations.Add(new Location(1.5f, 0.1f, -1.5f, 0.1f, 0.1f, 0.1f));
            iRobots.Locations.Add(new Location(0.5f, 0.1f, 0, 0.2f, 0.1f, 0.2f));
            iRobots.Locations.Add(new Location(-0.5f, 0.1f, 0, 0.2f, 0.1f, 0.2f));

            // load dal
            IDAL dal = new TestDAL();
            _hostingEnvironment = dal.LoadHostingEnvironment(_scenario.ScenarioName, _hostingEnvironment, 0, new List<Guid>());

            // add the fall back organisms
            _scenario.FallBackOrganisms = new List<IOrganism>(_hostingEnvironment.Organisms.Alive);

            try
            {
                // delete the old one if it exists
                _wsClient.DeleteScenario(_scenario.ScenarioName, _userId);
            }
            finally
            {
                // save it to file as well only for testing
                _scenario.Save();

                // save it
                int result = _wsClient.SaveScenario(_scenario, _wsClient.GetNewUserId(MACHINE_NAME, HOST_VERSION));
                _scenario.ScenarioName = null;
            }
        }

        /// <summary>
        /// not really a test just a method to save the survival of the fattest scenario
        /// </summary>
        [Test, Category("ScenarioCreate")]
        public void SaveScenarioSingleiRobotXML()
        {

            _hostingEnvironment = new MSRBHost(new MockHostingEnvironmentPhysical(), _scenario);
            _scenario.ScenarioName = "Single iRobot Organisms";
            _scenario.ScenarioDescription = "Single iRobot Organisms testing scenario";
            _scenario.SimulationRestrictions = typeof(SimpleSimulationRestrictions).ToString();
            // add the fall back organisms
            _scenario.FallBackOrganisms = new List<IOrganism>(_hostingEnvironment.Organisms.Alive);
            _scenario.RequiredOrganisms = new List<IScenarioEntityRequirements>();
            _hostingEnvironment = new MSRBHost(new MockHostingEnvironmentPhysical(), _scenario);
            var iRobots = new Scenario.ScenarioEntityRequirements();
            _scenario.RequiredOrganisms.Add(iRobots);
            iRobots.OrganismType = new iRobot(new Organism(_hostingEnvironment), Guid.NewGuid()) { Organism = null, Guid = Guid.Empty };

            iRobots.UseFallBackOnly = false;

            // add the location
            iRobots.Locations.Add(new Location(0f, 0.1f, 0, 0.2f, 0.1f, 0.2f));

            // load dal
            IDAL dal = new TestDAL();
            _hostingEnvironment = dal.LoadHostingEnvironment(_scenario.ScenarioName, _hostingEnvironment, 0, new List<Guid>());

            // add the fall back organisms
            _scenario.FallBackOrganisms = new List<IOrganism>(_hostingEnvironment.Organisms.Alive);

            // save it to file as well only for testing
            _scenario.Save();

            // save it
            _scenario.ScenarioName = null;

        }

        /// <summary>
        /// not really a test just a method to save the clean my house scenario
        /// </summary>
        [Test, Category("ScenarioCreate")]
        public void SaveScenarioCleanMyHouseWS()
        {
            CreateCleanMyHouseScenario("Clean my house", typeof(MNTABHD).ToString());
        }

        private void CreateCleanMyHouseScenario(string scenarioName, string fitnessFunction)
        {
            _scenario = new ScenarioLocalXML();
            _scenario.FitnessFunction = fitnessFunction;
            _scenario.ScenarioName = scenarioName;
            _scenario.ScenarioDescription = "This scenario is based around the roomba vacuming machine cleaning the house and not hitting the walls";
            _scenario.ManifestFile = "InABox.Manifest.xml";
            _scenario.BoundryXRadiusMax = 3.2f;
            _scenario.BoundryYRadiusMax = 2.5f;
            _scenario.BoundryZRadiusMax = 3.2f;
            _scenario.MaxLoadCount = 10;
            _scenario.MaxSaveCount = 11;
            _scenario.SimulationRestrictions = typeof(SimpleSimulationRestrictions).ToString();
            _scenario.RequiredOrganisms = new List<IScenarioEntityRequirements>();
            _hostingEnvironment = new MSRBHost(new MockHostingEnvironmentPhysical(), _scenario);
            var iRobots = new Scenario.ScenarioEntityRequirements();
            _scenario.RequiredOrganisms.Add(iRobots);
            iRobots.OrganismType = new iRobot(new Organism(_hostingEnvironment), Guid.NewGuid());

            // null out sub sections
            iRobots.OrganismType.Organism = null;
            iRobots.OrganismType.Guid = Guid.Empty;
            iRobots.UseFallBackOnly = false;

            // add the location
            iRobots.Locations.Add(new Location(0.5f, 0.1f, 0, 0.2f, 0.1f, 0.2f));
            iRobots.Locations.Add(new Location(-0.5f, 0.1f, 0, 0.2f, 0.1f, 0.2f));

            // load dal
            IDAL dal = new TestDAL();
            _hostingEnvironment = dal.LoadHostingEnvironment(_scenario.ScenarioName, _hostingEnvironment, 0, new List<Guid>());

            // add the fall back organisms
            _scenario.FallBackOrganisms = new List<IOrganism>(_hostingEnvironment.Organisms.Alive);

            try
            {
                // delete the old one if it exists
                _wsClient.DeleteScenario(_scenario.ScenarioName, _userId);
            }
            finally
            {
                // save it to file as well only for testing
                _scenario.Save();

                // save it
                int result = _wsClient.SaveScenario(_scenario, _wsClient.GetNewUserId(MACHINE_NAME, HOST_VERSION));
                _scenario.ScenarioName = null;
            }

        }

        /// <summary>
        /// not really a test just a method to save the clean my house scenario
        /// </summary>
        [Test, Category("ScenarioCreate")]
        public void SaveScenarioGenesisCleanMyHouseWS()
        {
            CreateCleanMyHouseScenario("Genesis Clean my house", typeof(GenesisMNTABHD).ToString());
        }

    }
}
